package com.sk.bilibili.utils;

import com.sk.bilibili.bean.Praise;
import com.sk.bilibili.other.RedisKeyGenerator;
import com.sk.bilibili.service.PraiseService;
import lombok.extern.java.Log;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.function.Predicate;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @author 邵康
 * @date 2021/12/19 10:48
 */
@Log
@Component
public class RedisUtils implements InitializingBean {

    @Autowired
    private StringRedisTemplate template;
    @Autowired
    private DbUtils dbUtils;
    @Lazy//延迟加载
    @Autowired
    private PraiseService praiseService;
    private static final Pattern NUM_KEY_PATTERN =Pattern.compile("([A-z]+)-(\\d+)");
    private static final Pattern PRAISE_KEY_PATTERN =Pattern.compile("(\\d+)-(\\d+)");
    private static final Pattern REWARD_KEY_PATTERN =Pattern.compile("\\d{1,7}");//防止匹配电话
    private Map<Class<?>, RedisKeyGenerator> cache;

    @Override
    public void afterPropertiesSet() throws Exception {
        cache=new HashMap<>();
    }

    public void set(String key,String value){
        template.opsForValue().set(key,value);
    }

    public void set(String key, String value, long time, TimeUnit timeUnit){
        template.opsForValue().set(key, value,time,timeUnit);
    }

    public String get(String key){
        return template.opsForValue().get(key);
    }

    public Boolean delete(String key) {
        return template.delete(key);
    }

    public Boolean contains(String key) {
        return template.hasKey(key);
    }

    public Boolean contains(String key,String field) {
        return template.opsForHash().hasKey(key,field);
    }

    public Long changeNum(Object target, String field, long num){
        String key=generateKey(target);
        return changeNum(key,field,num);
    }

    public Long changeNum(String key, String field, long num){
        return template.opsForHash().increment(key,field,num);
    }

    public Integer getNum(Object target,String field){
        String key = generateKey(target);
        return getNum(key,field);
    }

    public Integer getNum(String key,String field){
        Object res = template.opsForHash().get(key, field);
        if(res==null)return 0;
        return Integer.parseInt(res.toString());
    }

    private String generateKey(Object target) {
        Class<?> clazz = target.getClass();
        if(!cache.containsKey(clazz)){
            cache.put(clazz,new RedisKeyGenerator(clazz));
        }
        return cache.get(clazz).generateKey(target);
    }

    public void clearNum(Object target, Object... fields) {
        String key = generateKey(target);
        template.opsForHash().delete(key,fields);
    }

    public void flashNum() {
        Set<String> keys = template.keys("*");
        for (String key:keys){
            Matcher numMatcher = NUM_KEY_PATTERN.matcher(key);
            if(numMatcher.matches()){
                Map<Object, Object> entries = template.opsForHash().entries(key);
                String table= StringUtils.toUnderline(numMatcher.group(1));
                Integer id=Integer.parseInt(numMatcher.group(2));
                for (Map.Entry<Object,Object> entry:entries.entrySet()){
                    String column=StringUtils.toUnderline(entry.getKey().toString());
                    Integer num=Integer.parseInt(entry.getValue().toString());
                    dbUtils.changeNum(table,column,num,id);
                }
                template.delete(key);
            }
        }
    }

    public void flashPraise() {
        Set<String> keys = template.keys("*");
        for (String key:keys){
            Matcher praiseMatcher = PRAISE_KEY_PATTERN.matcher(key);
            if(praiseMatcher.matches()){
                Praise praise = new Praise();
                praise.setType(Integer.parseInt(praiseMatcher.group(1)));
                praise.setTargetId(Integer.parseInt(praiseMatcher.group(2)));
                Set<String> ids = template.opsForSet().members(key);
                for (String id:ids){
                    praise.setMemberId(Integer.parseInt(id));
                    praiseService.save(praise);
                }
                template.delete(key);
            }
        }
    }

    public Boolean hasPraise(int type, Integer targetId, int memberId) {
        String key=generateKey(type,targetId);
        return template.opsForSet().isMember(key,String.valueOf(memberId));
    }

    private String generateKey(int type, Integer targetId) {
        return String.format("%d-%d",type,targetId);
    }

    public Long removePraise(Praise praise) {
        String key = generateKey(praise.getType(), praise.getTargetId());
        return template.opsForSet().remove(key,praise.getMemberId().toString());
    }

    public void addPraise(Praise praise) {
        String key = generateKey(praise.getType(), praise.getTargetId());
        template.opsForSet().add(key,praise.getMemberId().toString());
    }

    public void clearDailyReward() {
        Set<String> keys = template.keys("*");
        for (String key:keys){//删除所有  奖励信息
            if(REWARD_KEY_PATTERN.matcher(key).matches()){
                template.delete(key);
            }
        }
    }

}
